package cn.org.wifit.core.zookeeper;

import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;


/**
 * 这个类在每个服务器端都是一个单例模式的对象。这个对象记录了一个从zookeeper上抽象出来的用xml格式表示的tree结构。<br>
 * <br>
 * 这个类主要是依靠各watcherHandle接口进行操作，也有一部分是直接在BootStartup类中操作（服务器启动的初始化时）。<br>
 * 但是这个类并不与zookeeper直接关联，只负责记录zookeeper的树形格式到本地。与zookeeper的操作交给了外层的*Manager类。
 * @author wenjie
 */
public class ServerNodeTree {
	private static final ServerNodeTree NODETREE = new ServerNodeTree();
	
	public static ServerNodeTree getNewInstance() {
		return ServerNodeTree.NODETREE;
	}
	
	/**
	 * XML文档的根节点
	 */
	private Element rootElement;
	
	private ServerNodeTree() {
		Document doc = new Document(new Element("root"));
		this.rootElement = doc.getRootElement();
		
		/*
		 * 首先要将一些持久节点直接添加到内存中包括了：
		 * /root/IMServer
		 * /root/IMUser
		 * /root/IMUser/ipxs
		 * */
		Element imserverEl = new Element("IMServer");
		Element imuserEl = new Element("IMUser");
		Element ipxsEl = new Element("ipxs");
		imuserEl.addContent(ipxsEl);
		
		this.rootElement.addContent(imserverEl);
		this.rootElement.addContent(imuserEl);
	}
	
	/**
	 * 添加系统中唯一一组IMUserver服务集群的根节点
	 * @param clusterDomain 
	 * @return 如果添加成功，则返回true；其他情况返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public synchronized boolean SetIMUserServer(String clusterDomain) {
		/*
		 * 如果已经存在这个节点，则不能进行重复添加。所以要进行判断
		 * 
		 * 新增IMUser节点时，应该把其下ipxs、IDSections节点也新增了（IDGroupSections节点暂时不用处理，因为还没有涉及到群聊的功能）
		 * */
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMUser");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		//如果条件成立，说明唯一的/root/IMUser节点已经被添加
		if(list != null && list.size() > 0) {
			return false;
		}
		
		//开始添加/root/IMUser
		Element imUserElement = new Element("IMUser");
		imUserElement.setAttribute("clusterDomain", clusterDomain);
		
		//添加/root/IMUser/ipxs
		Element ipxsElement = new Element("ipxs");
		imUserElement.addContent(ipxsElement);
		
		//添加/root/IMUser/IDSections
		Element idSectionsElement = new Element("IDSections");
		idSectionsElement.setAttribute("maxID", "0");
		imUserElement.addContent(idSectionsElement);
		root.addContent(imUserElement);
		
		return true;
	}
	
	/**
	 * 添加一个IMUserServer服务对应的ipx节点到/root/IMUser/ipxs节点下
	 * @param sequence 这是ipx节点的唯一名称，这个名称来源于zookeeper对这个节点的唯一编号
	 * @param ip 本次要添加的ipx的ip信息
	 * @param port 本次要添加的ipx的port信息
	 * @return 如果添加成功，则返回true，其他情况返回false
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public synchronized boolean AddIMUserServerNode(String sequence , String ip , Integer port) {
		/*
		 * 在添加前需要做两个维度的判断：
		 * 1、/root/IMUser/ipxs节点是否存在
		 * 2、将要添加的 /root/IMUser/ipxs/ipx节点属性是否重复（有三个属性都要进行判断）
		 * */
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMUser/ipxs");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		//如果条件成立，说明唯一的/root/IMUser节点已经被添加
		if(list == null || list.size() != 1) {
			return false;
		}
		Element ipxsElement = list.get(0);
		
		//判断sequence是否存在
		expressione = XPathFactory.instance().compile("/root/IMUser/ipxs/ipx[@sequence='" + sequence + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		
		//判断ip和port属性是否同时存在
		expressione = XPathFactory.instance().compile("/root/IMUser/ipxs/ipx[@ip='" + ip + "'][@port='" + port + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		
		//================以上判断通过后，就可以进行添加了
		Element ipxElement = new Element("ipx");
		ipxElement.setAttribute("sequence" , sequence);
		ipxElement.setAttribute("ip" , ip);
		ipxElement.setAttribute("port" , port.toString());
		ipxsElement.addContent(ipxElement);
		
		return true;
	}
	
	/**
	 * 移除指定的存储在本地的缓存中的imuser节点信息。调用这个方法的主要原因是远程zk上相应的imuser节点已经被注销了
	 * @param serverSequence 指定的imuser的序列信息
	 * @return 如果注销成功，则返回true；其他情况返回false
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public boolean removeIMUserServer(String serverSequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMUser/ipxs");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list == null || list.size() == 0) {
			return false;
		}
		Element imuserIPXSElement = list.get(0);
		
		expressione = XPathFactory.instance().compile("/root/IMUser/ipxs/ipx[@sequence='" + serverSequence + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		Element serverElement = list.get(0);
		
		//开始移除
		return imuserIPXSElement.removeContent(serverElement);
	}
	
	/**
	 * 将使用json返回目前本地所存储的所有/root/IMUser/ipxs/ipx<br>
	 * 使用json返回，避免了不必要的对象创建，也避免了xml对象向外界的暴露
	 * @return 返回格式为[{"sequence":"sequence","ip":ip,"port":port},{"sequence":"sequence","ip":ip,"port":port}]
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public String GetIMUserServerNodes() {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMUser/ipxs/ipx");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		
		String json = "[";
		for(int index = 0 ; list != null && index < list.size() ; index++) {
			Element ipxElement = list.get(index);
			if(index != 0) {
				json += ",";
			}
			json += "{\"sequence\":\"" + ipxElement.getAttribute("sequence").getValue() + "\",";
			json += "\"ip\":" + ipxElement.getAttribute("ip").getValue() + ",";
			json += "\"port\":" + ipxElement.getAttribute("port").getValue() + "";
			json += "}";
		}
		json += "]";
		return json;
	}
	
	/**
	 * 添加一组/root/IMServer/server节点。一组这个节点代表一个IMServer集群。
	 * @param sequence 由其他系统（一般是zookeeper服务）编号的为一个一组串号
	 * @param fromid 服务的id号的开始位置
	 * @param toid 服务的id号的结束位置
	 * @return 如果添加成功，则返回true；其他情况返回false
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public synchronized  boolean AddIMServer(String sequence , Integer fromid , Integer toid) {
		/*
		 * 再添加前需要完成的判断有
		 * 1、判断在/root/IMServer下有没有server[@sequence=sequence]的节点存在，如果有则不能重复添加
		 * 2、判断当前fromid和toid是否和现有的list[server]的fromid——toid有任何的交集，如果有任何交集，都不能进行添加
		 * */
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + sequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		if(fromid >= toid) {
			return false;
		}
		
		
		//得到现有的server所服务的所有范围
		expressione = XPathFactory.instance().compile("/root/IMServer/server");
		list = expressione.evaluate(root);
		for(int index = 0 ; index < list.size() ; index++) {
			Element serverElement = list.get(index);
			Integer _fromid = Integer.valueOf(serverElement.getAttributeValue("fromid"));
			Integer _toid = Integer.valueOf(serverElement.getAttributeValue("toid"));
			
			//如果成立，说明当前要添加fromid , toid在_fromid，_toid的范围之外
			if((fromid < _fromid && toid < _fromid)
				|| (fromid > _toid && toid > _toid)) {
				continue;
			} else {
				return false;
			}
		}
		
		//===============开始进行添加了
		expressione = XPathFactory.instance().compile("/root/IMServer");
		list = expressione.evaluate(root);
		Element imServerElement = list.get(0);
		
		Element server = new Element("server");
		server.setAttribute("sequence" , sequence);
		server.setAttribute("fromid" , fromid.toString());
		server.setAttribute("toid" , toid.toString());
		imServerElement.addContent(server);
		
		return true;
	}
	
	/**
	 * 在指定的/root/IMServer/server节点下，添加一个服务节点ipx
	 * @param serverSequence /root/IMServer/server节点的唯一编号，以便找到这个server节点
	 * @param ipxSequence ipx的唯一编号，这个编号有第三方确认（一般是zookeeper集群上节点的编号）
	 * @param ip ipx对应的服务ip
	 * @param port ipx对应的服务端口
	 * @param userport ipx服务为远程imuser服务提供的连接端口
	 * @return 如果添加成功，则返回true，否则返回false
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public synchronized  boolean AddIMServerIPX(String serverSequence , String ipxSequence , String ip , Integer port , Integer userport) {
		/*
		 * 在添加前，需要进行的验证包括：
		 * 1、验证/root/IMServer/server[@sequence=serverSequence]是否存在
		 * 2、验证/root/IMServer/server[@sequence=serverSequence]/ipx[@sequence=ipxSequence]是否不存在
		 * 3、验证/root/IMServer/server[@sequence=serverSequence]/ipx[@ip=ip][@port]是否不存在
		 * 4、验证/root/IMServer/server[@sequence=serverSequence]/ipx[@ip=ip][@userport]是否不存在
		 * */
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list == null || list.size() == 0) {
			return false;
		}
		
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']/ipx[@sequence='" + ipxSequence + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']/ipx[@ip='" + ip + "'][@port='" + port + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']/ipx[@ip='" + ip + "'][@userport='" + userport + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		
		//===============================开始进行添加
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']");
		list = expressione.evaluate(root);
		Element serverElement = list.get(0);
		
		Element ipxElement = new Element("ipx");
		ipxElement.setAttribute("sequence", ipxSequence);
		ipxElement.setAttribute("ip", ip);
		ipxElement.setAttribute("port", port.toString());
		ipxElement.setAttribute("userport", userport.toString());
		serverElement.addContent(ipxElement);
		
		return true;
	}
	
	/**
	 * 移除指定IMServer/server下的ipx节点
	 * @param serverSequence server节点的序号信息
	 * @param ipxSequence ipx节点的序号信息
	 * @return 如果移除成功，则返回true;其他情况返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean removeIMServerIPX(String serverSequence , String ipxSequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list == null || list.size() == 0) {
			return false;
		}
		Element serverElement = list.get(0);
		
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']/ipx[@sequence='" + ipxSequence + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		Element ipxElement = list.get(0);
		
		//开始移除
		return serverElement.removeContent(ipxElement);
	} 
	
	/**
	 * 移除指定IMServer下的server节点
	 * @param serverSequence server节点的序号信息
	 * @return 如果移除成功，则返回true;其他情况返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean removeServer(String serverSequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list == null || list.size() == 0) {
			return false;
		}
		Element imserverElement = list.get(0);
		
		expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']");
		list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return false;
		}
		Element serverElement = list.get(0);
		
		//开始移除
		return imserverElement.removeContent(serverElement);
	}
	
	/**
	 * 获取所有servers的信息，但是不包括这些server下的ipx信息
	 * @return 以json信息的方式返回
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public String GetIMServers() {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		
		String json = "[";
		for(int index = 0 ; list != null && index < list.size() ; index++) {
			Element serverElement = list.get(index);
			if(index != 0) {
				json += ",";
			} 
			
			String serverSequence = serverElement.getAttribute("sequence").getValue();
			String fromid = serverElement.getAttribute("fromid").getValue();
			String toid = serverElement.getAttribute("toid").getValue();
			json += "{\"sequence\":\"" + serverSequence + "\",\"fromid\":" + fromid + ",\"toid\":" + toid + "}";
		}
		json += "]";
		return json;
	}
		
	/**
	 * 获取指定的servers下的ipx信息。
	 * @param serverSequence 指定的server的编序号
	 * @return 以json信息的方式返回的一个数组
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public String GetIMServers(String serverSequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serverSequence + "']/ipx");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		String json = "[";
		for(int index = 0 ; list != null && index < list.size() ; index++) {
			Element ipxElement = list.get(index);
			if(index != 0) {
				json += ",";
			}
			
			String ipxSequence = ipxElement.getAttribute("sequence").getValue();
			String ip = ipxElement.getAttribute("ip").getValue();
			String port = ipxElement.getAttribute("port").getValue();
			String userport = ipxElement.getAttribute("userport").getValue();
				
			json += "{\"sequence\":\"" + ipxSequence + "\",\"ip\":\"" + ip + "\",\"port\":" + port + ",\"userport\":" + userport + "}";
		}
		json += "]";
		return json;
	}
	
	/**
	 * 查询在/root/IMServer节点下，是否存在
	 * /root/IMServer/server[@sequence='serversequence']的节点
	 * @param serversequence server的唯一序号
	 * @return 如果存在则返回true，其他情况返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean isServerExist(String serversequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serversequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return true;
		}
		
		return false;
	}
	
	
	
	/**
	 * 查询在/root/IMServer节点下，是否存在
	 * /root/IMServer/server[@sequence='serversequence']/ipx[@sequence='ipxsequence']的节点
	 * @param serversequence server的唯一序号
	 * @param ipxsequence ipx的唯一序号
	 * @return 如果存在则返回true，其他情况返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean isServeripxExist(String serversequence , String ipxsequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMServer/server[@sequence='" + serversequence + "']/ipx[@sequence='" + ipxsequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * 查询在/root/IMUser/ipxs节点下，是否存在
	 * /root/IMUser/ipxs/ipx[@sequence='ipxsequence']的节点
	 * @param ipxsequence
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean isUseripxExist(String ipxsequence) {
		XPathExpression expressione = XPathFactory.instance().compile("/root/IMUser/ipxs/ipx[@sequence='" + ipxsequence + "']");
		Element root = this.rootElement;
		List<Element> list = expressione.evaluate(root);
		if(list != null && list.size() > 0) {
			return true;
		}
		
		return false;
	}
	
// TODO 还没有涉及到群服务相关的业务
//	
//	public synchronized  void AddGroupServer() {
//		
//	}
//	
//	public synchronized  void AddGroupServerNode() {
//		
//	}
//	
//	public void GetGroupServers() {
//		
//	}
//	
//	public void GetGroupServerNodes() {
//		
//	}
}